package start.demo01.datatype.json.json;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import start.demo01.datatype.json.entity.OutputConfig;
import start.demo01.datatype.json.entity.builder.JSONEditorFactory;
import start.demo01.datatype.json.interfaces.Editor;
import start.demo01.datatype.json.interfaces.JSONEditor;
import start.demo01.datatype.json.pool.CacheMap;

import java.util.Iterator;
import java.util.LinkedList;

import static start.demo01.datatype.json.constant.Constant.*;

@Data
public class JSONPath implements Editor {

    private String name;//数据名称
    private CacheMap map;//缓存区
    private String path;
    private Object current;//当前元素

    private LinkedList<Node> nodes = new LinkedList<>();
    //一个路径多个操作
    private LinkedList<JSONEditor> editors = new LinkedList<>();

    @Override
    public void editor() {
        resolve((JSONObject) map.get(name));
    }

    public void resolve(JSONObject jsonObject) {
        resolve(nodes, jsonObject);
    }

    public void resolve(LinkedList<Node> nodes, Object obj) {
        resolve(0, nodes, obj);
    }

    //如履薄冰 勇猛精进
    public void resolve(int i, LinkedList<Node> nodes, Object obj) {
        for (; i < nodes.size() - 1; i++) {
            Node node = nodes.get(i);
            switch (node.type) {
                case NODE_TYPE1_1:
                    obj = ((JSONObject) obj).getJSONObject(node.key);
                    break;
                case NODE_TYPE1_2:
                    obj = ((JSONObject) obj).getJSONArray(node.key);
                    break;
                case NODE_TYPE2_1:
                    JSONArray branchs = branch(node.key, (JSONArray) obj);
                    for (Object o : branchs) {
                        resolve(i + 1, nodes, o);
                    }
                    return;
            }
        }
        //获取最后一个元素
        current = obj;
        Node node = nodes.getLast();
        Iterator<JSONEditor> iterator = editors.iterator();
        while (iterator.hasNext()) {
            JSONEditor next = iterator.next();
            next.setMap(map);
            next.apply(node, obj);
        }
    }

    //分头行动
    public static JSONArray branch(String key, JSONArray array) {
        if (key.equals(F)) {
            return array;
        }
        JSONArray jsonArray = new JSONArray();
        String[] indexs = key.split(",");
        for (String index : indexs) {
            jsonArray.add(array.get(Integer.parseInt(index)));
        }
        return jsonArray;
    }

    public static JSONPath builder(OutputConfig outputConfig, String cmd) {
        String[] arr = Editor.getName(cmd);
        return new JSONPath(outputConfig, arr[0], arr[1]);
    }

    public static JSONPath builder(OutputConfig outputConfig, String name, String path) {
        return new JSONPath(outputConfig, name, path);
    }


    public JSONPath(OutputConfig outputConfig, String name, String path) {
        this.name = name;
        path = path.trim();
        this.path = path;
        String[] split = path.split("\\.");
        for (String s : split) {
            if (s.matches("\\w+"))
                nodes.add(new Node(NODE_TYPE1_1, s));
            else if (s.matches("\\w+\\[.+\\]")) {
                int index = s.indexOf('[');
                nodes.add(new Node(NODE_TYPE1_2, s.substring(0, index)));
                s = s.substring(index + 1);
                String[] strs = s.split("\\[");
                for (String v : strs) {
                    nodes.add(new Node(NODE_TYPE2_1, v.substring(0, v.length() - 1)));
                }
            } else if (s.matches("\\w+\\(.*\\)")) {//函数
                int index = s.indexOf('(');
                String func = s.substring(0, index);
                String args = s.substring(index + 1, s.length() - 1);
                JSONEditor editor = JSONEditorFactory.get(func, args, outputConfig);
                if (editor != null)
                    editors.add(editor);
            }
        }
        if (nodes.size() == 0) {
            //操作当前对象
            nodes.add(new Node(NODE_TYPE1_1, null));
        }
    }

    @Data
    public class Node {

        private String type;
        private String key;

        public Node(String type, String key) {
            this.type = type;
            if (type.equals(NODE_TYPE2_1)) {
                this.key = getKey(key);
            } else
                this.key = key;
        }

        private String getKey(String key) {
            if (key.equals(F))
                return key;
            String[] split = key.split(",");
            StringBuilder builder = new StringBuilder();
            for (String s : split) {
                if (s.matches("\\d"))
                    builder.append(",").append(s);
                else if (s.matches("\\d+-\\d+")) {
                    int index = s.indexOf('-');
                    for (int i = Integer.parseInt(s.substring(0, index));
                         i <= Integer.parseInt(s.substring(index + 1)); i++) {
                        builder.append(",").append(i);
                    }
                }
            }
            return builder.substring(1);
        }
    }
}
